﻿using System;
using System.Collections.Generic;
using System.Linq;
using KLS.PPDS.Core.Entity;
using KLS.PPDS.Data.Database.Repository.EntityRepository;
using KLS.PPDS.Utility;
using KLS.PPDS.Utilities.Attributes;

namespace KLS.PPDS.ApplicationService.Manager
{
   public class ArticleManager:RepositoryManager<ArticleRepository>
    {
       /// <summary>
        /// assuming hole number is supplied to start page
       /// </summary>
       /// <param name="article"></param>
       /// <returns></returns>
       public static bool IsAppropiatePositionFound(Article article) 
       {
           var result = false;

           if (article.StartPage == null || article.StartPage == 0)
           {
               article.StartPage = null;
               article.EndPage = null;
               return true;
           }

           var startPage = article.StartPage.GetValueOrDefault(0);

           var endLoop = ((startPage + 1) - 0.25);

           for (double f = startPage; f <= endLoop; f = f + .25) 
           {
               article.StartPage = f;
               if (IsUnoccupied(article)) 
               {
                   return true;
               }
           }

          

               return result;
       }

       /// <summary>
       /// assuming strat page, end page and length is supplied 
       /// </summary>
       /// <param name="article"></param>
       /// <returns></returns>
       public static bool IsUnoccupied(Article article) 
       {

           //if (article.StartPage == null) 
           //{
           //    article.EndPage = null;
           //    return true;
           //}
           
           var result = false;
           var pubId = article.PublicationId;
           var artId = article.Id;

           var startPage = article.StartPage.GetValueOrDefault(0);
           var endPage = startPage + article.ExtentValue1.GetValueOrDefault(0) + article.ExtentValue2.GetValueOrDefault(0);

           if (endPage > PublicationManager.GetPageCountByPublicationId(article.PublicationId) + 1)
           {
               //update curretnt position
               article.EndPage = endPage;
               article.StartPage = startPage;

               return false;
           }

           //check if start page is occupied by another article
           bool isStartPageOccupied = ArticleManager.IsOccupied(pubId, artId, startPage);
           //check if end page is occupied by another article
           bool IsEndPageOccupied = ArticleManager.IsEndPageOccupied(pubId, artId, endPage);
           //check if there are  another article
           bool isOccupied = ArticleManager.IsOccupied(pubId, artId, startPage, endPage);

           //update curretnt position
           article.EndPage = endPage;
           article.StartPage = startPage;

           result = !(isStartPageOccupied || IsEndPageOccupied || isOccupied);

           return result;
       }

       /// <summary>
       /// delete
       /// </summary>
       /// <param name="art"></param>
       public static void Delete(Article art) 
       {
           Repository.Delete(art);
       }

       /// <summary>
       /// validate article during update/ add new
       /// </summary>
       /// <param name="article"></param>
       /// <returns></returns>
       public static bool Validate(Article article) 
       {
           var result = false;
           var pubId = article.PublicationId;
           var artId = article.Id;

          

           if (article.StartPage.HasValue)
           {
               var startPage = article.StartPage.GetValueOrDefault(0);

               //get maximum fraction used for any article
               var x = CommonTask.GetFraction(GetMaxEndPage(pubId, article.Id, Convert.ToInt32(startPage)));

               //set strat page
               if (artId > 0)// updating an existing article
               {
                   var y = Repository.GetArticleById(artId);

                   if (y.StartPage.HasValue )
                   {
                       // during update if strat page start from a different page
                       if (Convert.ToInt32(Math.Floor(y.StartPage.Value)) != Convert.ToInt32(Math.Floor(startPage)))
                       {
                           //configure new start page
                           startPage = startPage + x;
                       }
                       else // assigng preveious start page from db 
                       {
                           //previous stratpage assigned
                           startPage = y.StartPage.GetValueOrDefault(0);
                       }
                   }
                   else //drag from standby page to any page in the article
                   {
                       //configure new start page from stand by page
                       startPage = startPage + x;
                   }
               }
               else//new article
               {
                   // new article start page
                   startPage = startPage + x;
               }

               // configure end page
               article.EndPage = startPage + article.ExtentValue1.GetValueOrDefault(0) + article.ExtentValue2.GetValueOrDefault(0);
               var endPage = article.EndPage.GetValueOrDefault(0);

               //if end page excced publication page number
               if (endPage > PublicationManager.GetPageCountByPublicationId(article.PublicationId)+1) 
               {
                   return false;
               }

               //check if start page is occupied by another article
               bool isStartPageOccupied = ArticleManager.IsOccupied(pubId, artId, startPage);
               //check if end page is occupied by another article
               bool IsEndPageOccupied = ArticleManager.IsEndPageOccupied(pubId, artId, endPage);
               //check if there are  another article
               bool isOccupied = ArticleManager.IsOccupied(pubId, artId, startPage, endPage);

               result = !(isStartPageOccupied || IsEndPageOccupied || isOccupied);

               article.EndPage = endPage;
               article.StartPage = startPage;
           }
           else // stand by 
           {
               //set end-page null
               result = true;
               article.EndPage = null;
           }
           return result;
       }

       public  static void Save(Article article)
       {
           article.InitAudit();
           if (article.Id > 0)
           {
               var x = GetArticleById(article.Id);
               article.CopyPropertyValue<Article, Article>(x);

               Repository.Update(x);
               LogManager.LogDbUpdate(x);
           }
           else 
           {
               Repository.SaveAndEvict(article);
               LogManager.LogDbAdd(article);
           }
           
       }

       public static List<Article> GetAllArticle()
       {
           return Repository.GetAllArticle();
       }

       public static Article GetArticleById(int articleId)
       {

           return Repository.GetArticleById(articleId);
       }

       public static List<Article> GetArticleByPublicationId(int publicationId)
       {
           return Repository.GetArticleByPublicationId(publicationId);
       }

       public static List<Article> GetArticleByPublicationIdAndStartPage(int pubId, int artId, int pageNo) 
       {
           return Repository.GetArticleByPublicationIdAndStartPage(pubId, artId, pageNo);
       }

       /// <summary>
       /// check if there are other article inside a article while updating start page/ extension /end page 
       /// </summary>
       /// <param name="pubId"></param>
       /// <param name="articleId"></param>
       /// <param name="startPage"></param>
       /// <param name="endPage"></param>
       /// <returns></returns>
       public static bool IsOccupied(int pubId, int articleId, double startPage, double endPage)
       {
           return Repository.IsOccupied(pubId,  articleId, startPage, endPage);
       }

       /// <summary>
       /// Check if there is any article for a publication? retun true if occupide 
       /// </summary>
       /// <param name="pubId"></param>
       /// <param name="startPage"></param>
       /// <param name="endPage"></param>
       /// <returns></returns>
       public static bool IsOccupied(int pubId, double startPage, double endPage)
       {
           return Repository.IsOccupied(pubId,  startPage, endPage);
       }

       /// <summary>
       /// Check start page is occupied by other article? retun true if occupide 
       /// </summary>
       /// <param name="pubId"></param>
       /// <param name="articleId"></param>
       /// <param name="page"></param>
       /// <returns></returns>
       public static bool IsOccupied(int pubId, int articleId, double page)
       {
           return Repository.IsOccupied(pubId, articleId, page);
       }

       /// <summary>
       /// Check if current article end page is occupied by other article ? retun true if occupide
       /// </summary>
       /// <param name="pubId"></param>
       /// <param name="articleId"></param>
       /// <param name="page"></param>
       /// <returns></returns>
       public static bool IsEndPageOccupied(int pubId,int articleId, double page)
       {
           return Repository.IsEndPageOccupied(pubId, articleId, page);
       }

       /// <summary>
       /// Get maximum endpage with fraction for a perticular publication with perticular page 
       /// </summary>
       /// <param name="pubId"></param>
       /// <param name="pageNo"></param>
       /// <returns></returns>
       public static double GetMaxEndPage(int pubId, int articleId, int pageNo) 
       {
           var list = GetArticleByPublicationIdAndStartPage(pubId, articleId, pageNo);

          

           if (list != null && list.Count > 0) 
           {
               return list.Max(c => c.EndPage).GetValueOrDefault(0);
           }

           return 0;
       }

       public static User GetEditorUserByPublicationId(int pubId)
       {
           var pub = PublicationManager.GetPublicationById(pubId);
           return CompanyManager.GetEditorUserByCompanyId(pub.CompanyId);
       }

       public static User GetGraphicsUserByPublicationId(int pubId)
       {
           var pub = PublicationManager.GetPublicationById(pubId);
           return CompanyManager.GetGraphicsUserByCompanyId(pub.CompanyId);
       }

       public static List<Article> GetArticleByPageNo(int pubId, int pageNo) 
       {
           return Repository.GetArticleByPageNo(pubId, pageNo); 
       }

       /// <summary>
       /// return all standByPage for a publication
       /// </summary>
       /// <param name="publicationId"></param>
       /// <returns></returns>
       public static List<Article> GetAllStandByArticle(int publicationId)
       {
           return Repository.GetAllStandByArticle(publicationId);
       }
    }
}
